package math;

import java.util.*;

public class MathNodeDisplayer
{
    private static class Context
    {
        List<Boolean> hasSiblingAbove;
        List<MathNode> siblings;

        Context(List<Boolean> hasSiblingAbove,List<MathNode> siblings)
        {
            this.hasSiblingAbove = hasSiblingAbove;
            this.siblings = siblings;
        }
    }

    public static String getDisplay(MathNode root)
    {
        return getDisplay(root,new Context(List.of(),List.of(root)));
    }

    static List<MathNode> getChildren(MathNode node)
    {
        if(node == null)
        {
            return List.of();
        }

        if(node instanceof BinaryOperatorNode)
        {
            var bon = (BinaryOperatorNode)node;
            return List.of(bon.leftOperand,bon.rightOperand);
        }
        else if(node instanceof UnaryOperatorNode)
        {
            var uon = (UnaryOperatorNode)node;
            return List.of(uon.operand);
        }
        else if(node instanceof FunctionCallNode)
        {
            var fcn = (FunctionCallNode)node;
            return fcn.arguments;
        }
        else if(node instanceof VariableReferenceNode)
        {
            var vrn = (VariableReferenceNode)node;
            return List.of();
        }
        else if(node instanceof NumberNode)
        {
            var nn = (NumberNode)node;
            return List.of();
        }
        else 
        {
            throw new IllegalArgumentException("not supported to display: " + node.toString());
        }
    }

    public static String getDisplay(MathNode node,Context context)
    {
        StringBuilder builder = new StringBuilder();
        if(!context.hasSiblingAbove.isEmpty())
        {
            for(Boolean has : context.hasSiblingAbove)
            {
                if(has)
                {
                    builder.append("│   ");
                }
                else
                {
                    builder.append("    ");
                }
            }
            if(context.siblings.getLast() != node)
            {
                builder.append("├── ");
            }
            else
            {
                builder.append("└── ");
            }
        }
        builder.append(node.getName()).append("\n");

        var children = getChildren(node);
        for(var c : children)
        {
            List<Boolean> newHasSiblingAbove = new ArrayList<>(context.hasSiblingAbove);
            newHasSiblingAbove.add(context.siblings.get(context.siblings.size() - 1) == node ? false : true);
            builder.append(getDisplay(c,new Context(newHasSiblingAbove,children)));
        }

        return builder.toString();
    }
}



            




